﻿using System;
using System.Diagnostics;
using System.Drawing;
using System.Windows.Forms;
using MLRobotic.Tower.Common;
using System.Text;
using MLRobotic.Tower.Detection;

namespace MLRobotic.Tower.Forms
{
    public partial class DetectionForm : Form
    {
        private Log _log = new Log("DetectionForm");
        private Stopwatch _watch = new Stopwatch();

        private ConfigurationControl _configurationControl;
        private TabControl _calibrateTabs;
        private SerialPortsControl _serialPortsControl;

        private Timer _timer;

        private Config _config;
        private ControlTower _controlTower;

        private bool _autoFocus = false;
        private bool _zoom = true;
        private bool _matchStarted = false;

        public DetectionForm(ControlTower controlTower, Config config)
        {
            _controlTower = controlTower;
            _controlTower.FrameProcessed += OnFrame;
            
            _config = config;

            // Before InitializeComponent to be on top
            AddConfigurationControl();
            AddCalibrateControls();
            AddSerialPortscontrols();

            InitializeComponent();

            Load += DetectionForm_Load;

            if (!_config.IsTouchPro2())
            {
                pictureBox1.Width = 180;
                pictureBox1.Height = 240;
                pictureBox1.Location = new Point(30, 0);
            }
        }

        private void DetectionForm_Load(object sender, EventArgs e)
        {
            var error = _controlTower.Init();

            if (!string.IsNullOrEmpty(error))
                MessageBox.Show(error);

            _timer = new Timer { Interval = 50 };
            _timer.Tick += (s, a) => _controlTower.MainLoop();
            _timer.Enabled = true;

            btnFocus_Click(null, null);
        }

        private void AddConfigurationControl()
        {
            _configurationControl = new ConfigurationControl(_config) { Visible = false };
            this.Controls.Add(_configurationControl);
        }
        
        private void AddCalibrateControls()
        {
            var calibrateRed = new CalibrateControl { TargetColor = _config.Red };
            var calibrateBlue = new CalibrateControl { TargetColor = _config.Blue };
            var calibrateYellow = new CalibrateControl { TargetColor = _config.Yellow };
            var calibrateMagenta = new CalibrateControl { TargetColor = _config.Magenta };
            var calibrateGreen = new CalibrateControl { TargetColor = _config.Green };

            var tab1 = new TabPage { Text = "Red" };
            var tab2 = new TabPage { Text = "Blue" };
            var tab3 = new TabPage { Text = "Yellow" };
            var tab4 = new TabPage { Text = "Magenta" };
            var tab5 = new TabPage { Text = "Green" };

            tab1.Controls.Add(calibrateRed);
            tab2.Controls.Add(calibrateBlue);
            tab3.Controls.Add(calibrateYellow);
            tab4.Controls.Add(calibrateMagenta);
            tab5.Controls.Add(calibrateGreen);

            _calibrateTabs = new TabControl { Visible = false };
            _calibrateTabs.Height += 30;
            _calibrateTabs.SelectedIndexChanged += _calibrateTabs_SelectedIndexChanged;
            _calibrateTabs.TabPages.Add(tab1);
            _calibrateTabs.TabPages.Add(tab2);
            _calibrateTabs.TabPages.Add(tab3);
            _calibrateTabs.TabPages.Add(tab4);
            _calibrateTabs.TabPages.Add(tab5);
 
            this.Controls.Add(_calibrateTabs);
        }

        private void AddSerialPortscontrols()
        {
            _serialPortsControl = new SerialPortsControl(_controlTower, _config) { Visible = false };
            this.Controls.Add(_serialPortsControl);
        }

        private void OnFrame(object sender, ControlTower.FrameProcessedEventArgs e)
        {
            //this.Invoke(new Action<ControlTower.FrameProcessedEventArgs>(DisplayFrame), e);
            DisplayFrame(e);
        }

        private void DisplayFrame(ControlTower.FrameProcessedEventArgs e)
        {
            pictureBox1.Image = CropFrame(e.Frame);
            lblCandle1.Text = DisplayCandle(e.Candles, 0);
            lblCandle2.Text = DisplayCandle(e.Candles, 6);
            lblX1.Text = e.Beacon1.X.ToString();
            lblY1.Text = e.Beacon1.Y.ToString();
            lblX2.Text = e.Beacon2.X.ToString();
            lblY2.Text = e.Beacon2.Y.ToString();

            panelTeam.BackColor = _config.Team == Team.Blue ? Color.Blue : Color.Red;
            
            //string time = e.Duration.ToString() + " ms";
            string time = _watch.ElapsedMilliseconds.ToString() + " ms";
            lblT.Text = time;
            _log.Info("DisplayFrame : " + time);

            _watch.Reset();
            _watch.Start();
        }

        private Bitmap CropFrame(Bitmap frame)
        {
            if (!_zoom)
                return frame;

            var h = _config.Height / 3;
            var w = _config.Width / 3;
            Rectangle area = _config.Team == Team.Red ? new Rectangle(_config.Width - w, _config.Height - h, w, h)
                : new Rectangle(0, _config.Height - h, w, h);

            return BitmapHelper.CropImage(frame, area);
        }

        private string DisplayCandle(bool[] candles, int index)
        {
            StringBuilder sb = new StringBuilder();
            if (_config.Team == Team.Blue)
            {
                sb.Append(candles[index] ? "X " : "_ ");
                sb.Append(candles[index + 1] ? "X " : "_ ");
                sb.Append(candles[index + 2] ? "X " : "_ ");
                sb.Append(candles[index + 3] ? "X " : "_ ");
            }
            else
            {
                sb.Append(candles[index + 3] ? "X " : "_ ");
                sb.Append(candles[index + 2] ? "X " : "_ ");
                sb.Append(candles[index + 1] ? "X " : "_ ");
                sb.Append(candles[index ] ? "X " : "_ ");
            }
            return sb.ToString();
        }

        private void DetectionForm_Deactivate(object sender, EventArgs e)
        {
            _log.Info("Closing app");
            Log.Flush();
            _timer.Enabled = false;
            _timer.Dispose();
            Close();
        }

        private void btnFocus_Click(object sender, EventArgs e)
        {
            _autoFocus = !_autoFocus;
            _controlTower.AutoFocus(_autoFocus);
            btnFocus.Text = _autoFocus ? "On" : "Off";
        }

        private void btnConfig_Click(object sender, EventArgs e)
        {
            _calibrateTabs.Visible = false;
            _serialPortsControl.Visible = false;
            _configurationControl.Visible = !_configurationControl.Visible;
            _controlTower.CalibrateCandles();
        }

        private void btnCalibrate_Click(object sender, EventArgs e)
        {
            _configurationControl.Visible = false;
            _serialPortsControl.Visible = false;
            _calibrateTabs.Visible = !_calibrateTabs.Visible;

            if (_calibrateTabs.Visible)
                _calibrateTabs_SelectedIndexChanged(null, null);
        }

        private void btnCom_Click(object sender, EventArgs e)
        {
            _configurationControl.Visible = false;
            _calibrateTabs.Visible = false;
            _serialPortsControl.Visible = !_serialPortsControl.Visible;
            _controlTower.CalibrateCandles();
        }

        private void startButton_Click(object sender, EventArgs e)
        {
            _configurationControl.Visible = false;
            _calibrateTabs.Visible = false;
            _serialPortsControl.Visible = false;

            _matchStarted = !_matchStarted;
            btnStart.Text = _matchStarted ? "ReStart" : "Start";

            if (_matchStarted)
                _controlTower.ReadyForMatch();
            else
                _controlTower.CalibrateCandles();
        }

        private void _calibrateTabs_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (_calibrateTabs.SelectedIndex == 0 || _calibrateTabs.SelectedIndex == 1 || _calibrateTabs.SelectedIndex == 2)
                _controlTower.CalibrateCandles();
            else if (_calibrateTabs.SelectedIndex == 3 || _calibrateTabs.SelectedIndex == 4)
                _controlTower.CalibrateBeacons();
        }

        private void menuPixel_Click(object sender, EventArgs e)
        {
            _controlTower.DisplayPixels = !_controlTower.DisplayPixels;
        }

        private void menuZoom_Click(object sender, EventArgs e)
        {
            _zoom = !_zoom;
        }
    }
}